#!/bin/env python
"""
Publication service
"""
from common import *
import crypt
from optparse import OptionParser
import os
import pdb
import pexpect
import pgdb
import subprocess
import sys
import SXR_server as sxr
import uuid

# Configure below
# LISTEN_HOST='127.0.0.1' # You should not use '' here, unless you have a real FQDN.
# LISTEN_HOST='esg.ccs.ornl.gov'
# LISTEN_PORT=40001

# Configure this code in file 'pubsvc.cfg'

# ---------------------------------------------------------------------------
def main(HandlerClass = sxr.SecureXMLRpcRequestHandler,
         ServerClass = sxr.SecureXMLRPCServer):
    """
    Fire up the publication service using the key and cert file names
    from the SSL configuration, setting up the SSL configuration if
    necessary.
    """
    global cfg
    
    p = OptionParser()
    p.add_option('-d', '--debug',
                 action='store_true', default=False, dest='debug',
                 help="run under debugger")
    p.add_option('-v', '--verbose',
                 action='store_true', default=False, dest='verbose',
                 help="spew debugging info")
    (o, a) = p.parse_args(sys.argv)

    if o.debug:
        pdb.set_trace()
        
    cfg = get_config('pubsvc.cfg')
    hostname = cfg.get('DEFAULT', 'hostname')
    port = cfg.get('DEFAULT', 'port')
    
    (keyfile, certfile) = ssl_setup()
    if o.verbose:
        print("keyfile = '%s'" % keyfile)
        print("certfile = '%s'" % certfile)
              
    server_address = (hostname, int(port)) # (address, port)
    server = ServerClass(server_address, HandlerClass,
                         keyfile=keyfile,
                         certfile=certfile)
    server.register_instance(xmlrpc_registers())    
    sa = server.socket.getsockname()
    print "Serving HTTPS on", sa[0], "port", sa[1]
    server.serve_forever()

# ---------------------------------------------------------------------------
def ssl_setup():
    certdir = os.getenv('PUBSVC')
    if certdir == None:
        certdir = '%s/.pubsvc' % homedir()
    if not os.path.exists(certdir):
        raise StandardError("Can't find server certificate and key")
    return("%s/skey.pem" % certdir, "%s/scert.pem" % certdir)

# ---------------------------------------------------------------------------
def homedir():
    home = os.getenv('HOME')
    if home == None:
        home = pwd.getpwuid(os.getuid()).pw_dir
    return home

# ---------------------------------------------------------------------------
class xmlrpc_registers:
    # -----------------------------------------------------------------------
    def __init__(self):
        import string
        self.python_string = string
            
    # -----------------------------------------------------------------------
    def auth(self, user, passwd):
        global cfg

        go_dir = cfg.get('DEFAULT', 'go_dir')
        rval = auth_as_publisher(user, passwd)
        
        if not rval:
            print("auth failed for user %s" % user)
            z = uuid.UUID('0' * 32)
            return z.hex
        
        print("user %s authorized as a publisher" % user)
        rval = fetch_credential(user, passwd, go_dir)

        if not rval:
            print("attempt to fetch an ESG credential for %s failed" % user)
            z = uuid.UUID('0' * 32)
            return z.hex
        
        reqid = uuid.uuid4()
            
        # here we want to start a database record with status 'start'
        # db fields: uuid, status, 3 end point names, is-gc, user's openid,
        #            user's e-mail address, tranfer ids
        #

        return reqid.hex
        
    # -----------------------------------------------------------------------
    def goxfr(self, auth_token_str, go_username, go_endpoint, path):
        global cfg

        go_dir = cfg.get('DEFAULT', 'go_dir')
        credfn = cfg.get('DEFAULT', 'credential_filename')
        cmd = '%s/activate-endpoint %s %s "%s"' % (go_dir,
                                                   go_username,
                                                   '%s/%s' % (go_dir, credfn),
                                                   go_endpoint)
        print cmd

        # here we initiate the transfers
        
        # here we need to update the database record status to
        # 'transfer' based on auth_token in the request id field

        # !@! somewhere, we have to monitor the active transfers,
        # notice when they complete, carry out the publish steps, and
        # notify the user that the task is done

        return 'OK'
    
    # -----------------------------------------------------------------------
    def testssl(self):
        print("routine testssl tickled")
        return True
    
# ---------------------------------------------------------------------------
def auth_as_publisher(openid, passwd):
    password = get_pg_password()
    cxn = pgdb.connect(database = 'esgcet',
                       user = 'dbsuper',
                       password = password)

    cur = cxn.cursor()

    # get the user information from the database
    cur.execute("select id, email, password from esgf_security.user"
                + " where openid = '%s'" % openid)
    row = cur.fetchall()
    userid = row[0][0]
    email = row[0][1]
    cpwd = row[0][2]
    if crypt.crypt(passwd, cpwd) != cpwd:
        # the password doesn't match -- authentication fails
        cur.close()
        cxn.close()
        return False

    # get the role_id that represents 'publisher'
    cur.execute("select id from esgf_security.role where name = 'publisher'")
    row = cur.fetchall()
    roleid = row[0][0]

    # Is the user a publisher?
    cur.execute("select * from esgf_security.permission"
                + " where user_id = %s and role_id = %d"
                % (userid, roleid))
    row = cur.fetchall()
    if row == []:
        # authorization fails -- the user is not a publisher
        cur.close()
        cxn.close()
        return False

    # All tests passed -- the user is valid and a publisher
    cur.close()
    cxn.close()
    return True
    
# ---------------------------------------------------------------------------
def get_pg_password():
    rval = os.getenv('ESG_PASSWORD')
    if rval == None:
        f = open("/esg/config/.esg_pg_pass")
        rval = f.readline().strip()
        f.close()
    return rval

# ---------------------------------------------------------------------------
if __name__ == '__main__':
    main()
